package com.transaction.common.util;

import java.util.Random;

/**
 * 随机生成中文名和身份证号码
 */
public class PerSonUtil {
    //百家姓
    static final String FAMILY_NAMES =
            "赵,钱,孙,李,周,吴,郑,王,冯,陈,褚,卫,蒋,沈,韩,杨,朱,秦,尤,许,何,吕,施,张," +
                    "孔,曹,严,华,金,魏,陶,姜,戚,谢,邹,喻,柏,水,窦,章,云,苏,潘,葛,奚,范,彭,郎," +
                    "鲁,韦,昌,马,苗,凤,花,方,俞,任,袁,柳,酆,鲍,史,唐,费,廉,岑,薛,雷,贺,倪,汤," +
                    "滕,殷,罗,毕,郝,邬,安,常,乐,于,时,傅,皮,卞,齐,康,伍,余,元,卜,顾,孟,平,黄," +
                    "和,穆,萧,尹,姚,邵,湛,汪,祁,毛,禹,狄,米,贝,明,臧,计,伏,成,戴,谈,宋,茅,庞," +
                    "熊,纪,舒,屈,项,祝,董,梁,杜,阮,蓝,闵,席,季,麻,强,贾,路,娄,危,江,童,颜,郭," +
                    "梅,盛,林,刁,钟,徐,邱,骆,高,夏,蔡,田,樊,胡,凌,霍,虞,万,支,柯,昝,管,卢,莫," +
                    "经,房,裘,缪,干,解,应,宗,丁,宣,贲,邓,郁,单,杭,洪,包,诸,左,石,崔,吉,钮,龚," +
                    "程,嵇,邢,滑,裴,陆,荣,翁,荀,羊,於,惠,甄,麴,家,封,芮,羿,储,靳,汲,邴,糜,松," +
                    "井,段,富,巫,乌,焦,巴,弓,牧,隗,山,谷,车,侯,宓,蓬,全,郗,班,仰,秋,仲,伊,宫," +
                    "宁,仇,栾,暴,甘,钭,厉,戎,祖,武,符,刘,景,詹,束,龙,叶,幸,司,韶,郜,黎,蓟,薄," +
                    "印,宿,白,怀,蒲,邰,从,鄂,索,咸,籍,赖,卓,蔺,屠,蒙,池,乔,阴,郁,胥,能,苍,双," +
                    "闻,莘,党,翟,谭,贡,劳,逄,姬,申,扶,堵,冉,宰,郦,雍,郗,璩,桑,桂,濮,牛,寿,通," +
                    "边,扈,燕,冀,郏,浦,尚,农,温,别,庄,晏,柴,瞿,阎,充,慕,连,茹,习,宦,艾,鱼,容," +
                    "向,古,易,慎,戈,廖,庾,终,暨,居,衡,步,都,耿,满,弘,匡,国,文,寇,广,禄,阙,东," +
                    "欧,殳,沃,利,蔚,越,夔,隆,师,巩,库,聂,晁,勾,敖,融,冷,訾,辛,阚,那,简,饶,空," +
                    "曾,母,沙,乜,养,鞠,须,丰,巢,关,蒯,相,查,后,荆,红,游,竺,权,逯,盖,益,桓,公," +
                    "万俟,司马,上官,欧阳,夏侯,诸葛,闻人,东方," +
                    "赫连,皇甫,尉迟,公羊,澹台,公冶,宗政,濮阳," +
                    "淳于,单于,太叔,申屠,公孙,仲孙,轩辕,令狐," +
                    "钟离,宇文,长孙,慕容,鲜于,闾丘,司徒,司空";

    //行政区编号
    static final String COUNTY_CODES = "640000,640100,640104,640105,640106,640121,640122,640181,640200,640202,640205," +
            "640221,640300,640302,640303,640323,640324,640381,640400,640402,640422,640423,640424,640425,640500,640502," +
            "640521,640522,650000,650100,650102,650103,650104,650105,650106,650107,650109,650121,650200,650202,650203," +
            "650204,650205,652100,652101,652122,652123,652200,652201,652222,652223,652300,652700,652800,652900,653000," +
            "653100,653125,653200,653226,654200,654202,654300,659001,659002,659003,659004,820000";


    static final Random random = new Random();

    /**
     * 生成中文名称
     * @return
     */
    public static String generateChinaName(){
        String[] familyNames = FAMILY_NAMES.split(",");
        String familyName = familyNames[random.nextInt(familyNames.length)];
        StringBuilder name = new StringBuilder(familyName);
        int num = random.nextInt(2) + 1;
        for(int i = 0;i < num;i++){
            name.append(generateChinese());
        }
        return name.toString();
    }

    /**
     * 生成身份证号码
     * @return
     */
    public static String generateIdCard(){
        return buildIdentityNo(buildPrefix17(randomCounty(),randomBirthDay(),randomLocation(),randomSex()));
    }


    /**
     * 生成汉字
     */
    static String generateChinese(){
        int highPos = (176 + Math.abs(random.nextInt(39)));//获取高位值
        int lowPos = (161 + Math.abs(random.nextInt(93)));//获取低位值

        byte[] b = new byte[2];

        b[0] = (new Integer(highPos).byteValue());
        b[1] = (new Integer(lowPos).byteValue());

        String str = null;//转成中文
        try {
            str = new String(b, "GBk");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return str;
    }

    /**
     * 随机一个城市
     */
    static String randomCounty(){
        String[] countyCodes = COUNTY_CODES.split(",");
        String countryCode = countyCodes[random.nextInt(countyCodes.length)];
        return countryCode;
    }

    /**
     * 随机一个出生日期
     */
    static String randomBirthDay() {
        StringBuilder birthDay = new StringBuilder();
        Integer year = 1921 + random.nextInt(90);
        Integer month = random.nextInt(12) + 1;
        Integer day = random.nextInt(30) + 1;
        if (month == 2) {
            day = 28;
        }

        birthDay.append(year);

        if(String.valueOf(month).length() < 2){
            birthDay.append("0").append(month);
        }else{
            birthDay.append(month);
        }

        if(String.valueOf(day).length() < 2){
            birthDay.append("0").append(day);
        }else{
            birthDay.append(day);
        }

        return birthDay.toString();
    }

    /**
     * 随机一个警局所在地
     */
    static String randomLocation(){
        return String.valueOf(random.nextInt(90) + 10);
    }

    /**
     * 随机一个性别
     */
    static String randomSex(){
        return String.valueOf(random.nextInt(10));
    }

    /**
     * 组装身份证前17位数字
     */
    static String buildPrefix17(String countryCode,
                                String birthday,
                                String location,
                                String sex) {

        StringBuilder prefix = new StringBuilder();
        prefix.append(countryCode)
                .append(birthday)
                .append(location)
                .append(sex);
        return prefix.toString();
    }

    /**
     * 根据前17位生成最后一位，并组装
     */
    static String buildIdentityNo(String prefix) {
        //1.step1,2
        Integer sum = executeStepOneAndTwo(prefix);
        //2.step3,4
        String identityNo = executeStepThreeAndFour(prefix,sum);

        return identityNo;
    }

    /**
     * 计算身份证前17位的和
     * 第一步：
     * 将身份证号码的第1位数字与7相乘；
     * 将身份证号码的第2位数字与9相乘；
     * 将身份证号码的第3位数字与10相乘；
     * 将身份证号码的第4位数字与5相乘；
     * 将身份证号码的第5位数字与8相乘；
     * 将身份证号码的第6位数字与4相乘；
     * 将身份证号码的第7位数字与2相乘；
     * 将身份证号码的第8位数字与1相乘；
     * 将身份证号码的第9位数字与6相乘；
     * 将身份证号码的第10位数字与3相乘；
     * 将身份证号码的第11位数字与7相乘；
     * 将身份证号码的第12位数字与9相乘；
     * 将身份证号码的第13位数字与10相乘；
     * 将身份证号码的第14位数字与5相乘；
     * 将身份证号码的第15位数字与8相乘；
     * 将身份证号码的第16位数字与4相乘；
     * 将身份证号码的第17位数字与2相乘。
     *
     * 第二步：将第一步身份证号码1~17位相乘的结果求和，全部加起来。
     */
    static Integer executeStepOneAndTwo(String prefix) {
        int length = prefix.length();
        int sum = 0;
        for(int i = 0; i < length; i++){
            switch (i){
                case 0 :
                case 10 :
                    sum += (prefix.charAt(i)-'0') * 7;break;

                case 2 :
                case 12 :
                    sum += (prefix.charAt(i)-'0') * 10;break;

                case 3 :
                case 13 :
                    sum += (prefix.charAt(i)-'0') * 5;break;

                case 4 :
                case 14 :
                    sum += (prefix.charAt(i)-'0') * 8;break;

                case 5 :
                case 15 :
                    sum += (prefix.charAt(i)-'0') * 4;break;

                case 6 :
                case 16 :
                    sum += (prefix.charAt(i)-'0') * 2;break;

                case 1 :
                case 11 :
                    sum += (prefix.charAt(i)-'0') * 9;break;

                case 7 : sum += (prefix.charAt(i)-'0') * 1;break;
                case 8 : sum += (prefix.charAt(i)-'0') * 6;break;
                case 9 : sum += (prefix.charAt(i)-'0') * 3;break;
            }
        }
        return sum;
    }

    /**
     * 计算最后一位
     * 第三步：用第二步计算出来的结果除以11，
     * 这样就会出现余数为0，余数为1，余数为2，余数为3，余数为4，余数为5，余数为6，余数为7，余数为8，余数为9，
     * 余数为10共11种可能性。
     *
     * 第四步：
     * 如果余数为0，那对应的最后一位身份证的号码为1；
     * 如果余数为1，那对应的最后一位身份证的号码为0；
     * 如果余数为2，那对应的最后一位身份证的号码为X；
     * 如果余数为3，那对应的最后一位身份证的号码为9；
     * 如果余数为4，那对应的最后一位身份证的号码为8；
     * 如果余数为5，那对应的最后一位身份证的号码为7；
     * 如果余数为6，那对应的最后一位身份证的号码为6；
     * 如果余数为7，那对应的最后一位身份证的号码为5；
     * 如果余数为8，那对应的最后一位身份证的号码为4；
     * 如果余数为9，那对应的最后一位身份证的号码为3；
     * 如果余数为10，那对应的最后一位身份证的号码为2。
     */
    static String executeStepThreeAndFour(String prefix, Integer sum) {
        String suffix = "";
        int remainder = sum % 11;
        switch (remainder){
            case 0 : suffix = "1";break;
            case 1 : suffix = "0";break;
            case 2 : suffix = "X";break;
            case 3 : suffix = "9";break;
            case 4 : suffix = "8";break;
            case 5 : suffix = "7";break;
            case 6 : suffix = "6";break;
            case 7 : suffix = "5";break;
            case 8 : suffix = "4";break;
            case 9 : suffix = "3";break;
            case 10 : suffix = "2";break;
        }
        prefix += suffix;
        return  prefix;
    }
}
